using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Zsa.Emulation.Memory
{
    /// <summary>
    /// A memory block
    /// </summary>
    [StructLayout(LayoutKind.Sequential,Pack=2,Size=8)]
    public struct MemoryBlock
    {
        #region Fields
        /// <summary>
        /// The start of the block.
        /// </summary>
        [CLSCompliant(false)]
        public readonly ushort BlockAddress;

        /// <summary>
        /// The unsigned 2 byte length.
        /// </summary>
        [CLSCompliant(false)]
        public readonly ushort BlockLength;

        /// <summary>
        /// The index of the item in the IMemory array that handles this block.
        /// </summary>
        internal readonly ushort _BlockIndex;

        /// <summary>
        /// The block offset.
        /// </summary>
        internal readonly ushort _BlockOffset;
        #endregion Fields

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="T:MemoryBlock"/> class.
        /// </summary>
        /// <param name="address">The address.</param>
        /// <param name="length">The length.</param>
        public MemoryBlock(int address, int length)
            : this(address, length, address, 0)
        {
        }

        public MemoryBlock(int address, int length, int blockOffset)
            : this ( address, length, blockOffset, 0 )
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:MemoryBlock"/> class.
        /// </summary>
        /// <param name="address">The address.</param>
        /// <param name="data">The data.</param>
        public MemoryBlock(int address, int length, int blockOffset, int blockIndex)
        {
            BlockAddress = (ushort)address;
            BlockLength = (ushort)length;
            _BlockIndex = (ushort)blockIndex;
            _BlockOffset = (ushort)blockOffset;
        }
        #endregion Constructors

        #region Properties
        /// <summary>
        /// Gets the address.
        /// </summary>
        /// <value>The address.</value>
        public int Address
        {
            get
            {
                return BlockAddress;
            }
        }

        /// <summary>
        /// Gets the end address.
        /// </summary>
        /// <value>The end address.</value>
        public int EndAddress
        {
            get
            {
                return BlockAddress + BlockLength;
            }
        }

        /// <summary>
        /// Gets the length.
        /// </summary>
        /// <value>The length.</value>
        public int Length
        {
            get
            {
                return BlockLength;
            }
        }

        /// <summary>
        /// Gets the source stream offset.
        /// </summary>
        /// <value>The source stream offset.</value>
        public int SourceStreamOffset
        {
            get
            {
                return _BlockOffset;
            }
        }

        /// <summary>
        /// Gets the index of the source.
        /// </summary>
        /// <value>The index of the source.</value>
        public int SourceIndex
        {
            get
            {
                return _BlockIndex;
            }
        }
        #endregion Properties

        #region Methods
        /// <summary>
        /// Determines whether the specified address contains address.
        /// </summary>
        /// <param name="address">The address.</param>
        /// <returns>
        /// 	<c>true</c> if the specified address contains address; otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsAddress(ushort address)
        {
            return ContainsAddress((int)address);
        }

        /// <summary>
        /// Determines whether the specified address contains address.
        /// </summary>
        /// <param name="address">The address.</param>
        /// <returns>
        /// 	<c>true</c> if the specified address contains address; otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsAddress(int address)
        {
            return address >= BlockAddress && address < (BlockAddress + BlockLength);
        }

        /// <summary>
        /// Gets the length of an adress in the stream.
        /// </summary>
        /// <param name="address">The address.</param>
        /// <param name="count">The count.</param>
        /// <returns></returns>
        [CLSCompliant(false)]
        public ushort GetLength(ushort address, ushort count)
        {
            int _BlockEnd = (BlockAddress + BlockLength);
            if (address >= BlockAddress && address < _BlockEnd)
            {
                int _Count = _BlockEnd - address;
                return (ushort)(_Count < count ? _Count : count); 
            }
            return 0;

        }
        #endregion Methods

    }
}

